package mapper

import (
	"fmt"
	"log"

	"gitee.com/rainsuperman/mapper_orm/mapper_core"
)

func SelectCount(query MapperQuery) int64 {
	if GetConfig().DefaultSqlDB == nil {
		panic("DefaultSqlDB is nil")
	}
	return SelectCountMust(GetConfig().DefaultSqlDB, query)
}

func SelectCountMust(dbOrTxObj any, query MapperQuery) int64 {
	tt, err := SelectCountWithErr(dbOrTxObj, query)
	if err != nil {
		panic(err)
	}
	return tt
}

func SelectCountWithErr(dbOrTxObj any, query MapperQuery) (int64, error) {

	sqlSelectStr := " COUNT(*) "
	sqlFromStr, argsFrom, err0 := FinalFromStr(query)
	if err0 != nil {
		return 0, err0
	}
	sqlEndStr, argsEnd, err1 := FinalEndStr(query, false, true)
	if err1 != nil {
		return 0, err1
	}

	args := append(argsFrom, argsEnd...)

	if GetConfig().Debug {
		log.Println("Select " + sqlSelectStr + sqlFromStr + sqlEndStr)
		log.Println(args)
	}

	t, err := mapper_core.SelectOneMapBase(dbOrTxObj, sqlSelectStr, sqlFromStr, sqlEndStr, args)
	if err != nil {
		return 0, err
	}
	if t == nil {
		return 0, fmt.Errorf("查询到的返回数量异常")
	}

	if len(t) != 1 {
		return 0, fmt.Errorf("查询到的返回数量异常, 数量为: %d", len(t))
	}

	for _, v := range t {
		return *v.(*int64), nil
	}

	return 0, fmt.Errorf("未处理异常")
}

// 根据id查询
func SelectById[T DbEntity](id int64) *T {

	if GetConfig().DefaultSqlDB == nil {
		panic("DefaultSqlDB is nil")
	}

	return SelectByIdMust[T](GetConfig().DefaultSqlDB, id)
}

// 根据id查询
func SelectByIdMust[T DbEntity](dbOrTxObj any, id int64) *T {

	tt, err := SelectByIdWithErr[T](dbOrTxObj, id)
	if err != nil {
		panic(err)
	}

	return tt
}

func SelectByIdWithErr[T DbEntity](dbOrTxObj any, id int64) (*T, error) {
	tt, err := SelectOneWithErr(dbOrTxObj, *NewQueryWithT[T]().Eq(GetConfig().IdColumnName, id))
	if err != nil {
		return nil, err
	}

	if tt == nil {
		return nil, nil
	}

	t, err := MapToStruct[T](tt)
	if err != nil {
		return nil, err
	}

	return t, nil
}

func SelectOne(query MapperQuery) map[string]any {
	if GetConfig().DefaultSqlDB == nil {
		panic("DefaultSqlDB is nil")
	}
	return SelectOneMust(GetConfig().DefaultSqlDB, query)
}

func SelectOneMust(dbOrTxObj any, query MapperQuery) map[string]any {

	tt, err := SelectOneWithErr(dbOrTxObj, query)
	if err != nil {
		panic(err)
	}
	return tt
}

func SelectOneWithErr(dbOrTxObj any, query MapperQuery) (map[string]any, error) {

	sqlSelectStr, argsSelect, err0 := FinalSelectStr(query)
	if err0 != nil {
		return nil, err0
	}
	sqlFromStr, argsFrom, err1 := FinalFromStr(query)
	if err1 != nil {
		return nil, err1
	}
	sqlEndStr, argsEnd, err2 := FinalEndStr(query, true, true)
	if err2 != nil {
		return nil, err2
	}

	args := append(append(argsSelect, argsFrom...), argsEnd...)

	if GetConfig().Debug {
		log.Println("Select " + sqlSelectStr + sqlFromStr + sqlEndStr)
		log.Println(args)
	}
	t, err := mapper_core.SelectOneMapBase(dbOrTxObj, sqlSelectStr, sqlFromStr, sqlEndStr, args)
	if err != nil {
		return nil, err
	}
	if t == nil || len(t) == 0 {
		return nil, nil
	}
	return t, nil

}

func SelectList(query MapperQuery) []map[string]any {

	if GetConfig().DefaultSqlDB == nil {
		panic("DefaultSqlDB is nil")
	}
	return SelectListMust(GetConfig().DefaultSqlDB, query)
}

func SelectListMust(dbOrTxObj any, query MapperQuery) []map[string]any {

	tt, err := SelectListWithErr(dbOrTxObj, query)
	if err != nil {
		panic(err)
	}
	return tt
}

func SelectListWithErr(dbOrTxObj any, query MapperQuery) ([]map[string]any, error) {

	sqlSelectStr, argsSelect, err0 := FinalSelectStr(query)
	if err0 != nil {
		return nil, err0
	}
	sqlFromStr, argsFrom, err1 := FinalFromStr(query)
	if err1 != nil {
		return nil, err1
	}
	sqlEndStr, argsEnd, err2 := FinalEndStr(query, true, true)
	if err2 != nil {
		return nil, err2
	}

	args := append(append(argsSelect, argsFrom...), argsEnd...)

	if GetConfig().Debug {
		log.Println("Select " + sqlSelectStr + sqlFromStr + sqlEndStr)
		log.Println(args)
	}
	return mapper_core.SelectListMapBase(dbOrTxObj, sqlSelectStr, sqlFromStr, sqlEndStr, args)

}

func SelectPage(page, size int, query MapperQuery) Page[map[string]any] {

	if GetConfig().DefaultSqlDB == nil {
		panic("DefaultSqlDB is nil")
	}
	return SelectPageMust(GetConfig().DefaultSqlDB, page, size, query)
}
func SelectPageMust(dbOrTxObj any, page, size int, query MapperQuery) Page[map[string]any] {

	tt, err := SelectPageWithErr(dbOrTxObj, page, size, query)

	if err != nil {
		panic(err)
	}
	return tt
}

func SelectPageWithErr(dbOrTxObj any, page, size int, query MapperQuery) (Page[map[string]any], error) {
	rePage := Page[map[string]any]{}

	if size > GetConfig().MaxPageNum {
		size = GetConfig().MaxPageNum
	}

	rePage.Page = page
	rePage.Size = size

	count, errCount := SelectCountWithErr(dbOrTxObj, query)

	if errCount != nil {
		return rePage, errCount
	}

	rePage.Total = count

	query.pageMark = Ptr(fmt.Sprintf("LIMIT %d,%d", (page-1)*size, size))
	ts, err := SelectListWithErr(dbOrTxObj, query)

	if err != nil {
		return rePage, err
	}
	// 遍历 ts 切片，将每个元素的指针添加到 rePage.Record 中
	rePage.Record = make([]map[string]any, len(ts))
	for i := range ts {
		var item map[string]any = ts[i]
		rePage.Record[i] = item
	}

	return rePage, nil

}
